package org.kalai.unifypay.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.kalai.unifypay.Constant;
import org.kalai.unifypay.Result;
import org.kalai.unifypay.bean.Partner;
import org.kalai.unifypay.bean.Transflow;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class CommonUtil {
	private static final Logger logger = Logger.getLogger(CommonUtil.class);
	//常用response返回数据
	public static void responseObject(HttpServletResponse response, String result){
		try {
			response.setContentType("application/json; charset=utf-8");
			PrintWriter out = response.getWriter();
			out.write(result);
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static String getResponse(HttpServletRequest request){
		try {
			// 读取请求内容
			BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
			String line = null;
			StringBuilder sb = new StringBuilder();
			while((line = br.readLine())!=null) sb.append(line);
			return sb.toString();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public static Map<String, Object> createRespMap(String respCode, String respMsg){
		Map<String, Object> map = new HashMap<>();
		map.put("respCode", respCode);
		map.put("respDesc", respMsg);
		return map;
	}
	
	public static Map<String, Object> createRespMap(String respCode, String respMsg, Map<String, Object> map){
		Map<String, Object> respMap = createRespMap(respCode, respMsg);
		respMap.putAll(map);
		return respMap;
	}
	
	//验证请求加密
	public static Map<String, String> validate(HttpServletRequest request, HttpServletResponse response){
		String partnerCode = request.getParameter("partnerCode");
		String encryptData = request.getParameter("encryptData");
		String signData = request.getParameter("signData");
		if (StringUtil.isEmpty(partnerCode, encryptData, signData)) {
			logger.error("请求参数不正确：partnerCode="+partnerCode);
			logger.error("请求参数不正确：encryptData="+encryptData);
			logger.error("请求参数不正确：signData="+signData);
			responseObject(response, new Result("100", "请求参数不正确").toString());
			return null;
		}
		Partner partner = DataDao.getInstance().getPartnerByCode(partnerCode);
		if (partner == null) {
			logger.error("合作方不存在：partnerCode="+partnerCode);
			responseObject(response, new Result("101", "合作方不存在").toString());
			return null;
		}
		String jsonData = new String(CipherUtils.decryptBase64(encryptData));
		if (CipherUtils.encryptMD5(jsonData+partner.getPartnerSecret()).equals(signData.toUpperCase())) {
			Map<String, String> map = new HashMap<>();
			try {
				JSONObject jsonObject = JSON.parseObject(jsonData);
				for (String key : jsonObject.keySet()) {
					map.put(key, jsonObject.getString(key));
				}
				return map;
			} catch (Exception e) {
				logger.error("报文数据解析失败："+jsonData);
				responseObject(response, new Result("102", "报文数据解析失败").toString());
				return null;
			}
		} else {
			logger.error("签名校验失败：partnerCode="+partnerCode);
			logger.error("签名校验失败：encryptData="+encryptData);
			logger.error("签名校验失败：signData="+signData);
			responseObject(response, new Result("102", "签名校验失败").toString());
			return null;
		}
	}
	
	public static void notifyMessage(final String notifyUrl, final String partnerCode, final String secret, final String tranxSN, 
			final String orderNo, final double transAmt, final String respCode, final String respDesc){
		new Thread(new Runnable() {
			@Override
			public void run() {
				Map<String, Object> params = new HashMap<String, Object>();
				try {
					params.put("tranxSN", tranxSN);
					params.put("orderNo", orderNo);
					params.put("transAmt", transAmt);
					params.put("respCode", respCode);
					params.put("respDesc", respDesc);
					String jsonData = JSON.toJSONString(params);
					params.clear();
					params.put("partnerCode", partnerCode);
					params.put("encryptData", CipherUtils.encryptBase64(jsonData.getBytes()));
					params.put("signData", CipherUtils.encryptMD5(jsonData+secret));
					final long MINUTE = 1000 * 60;
					long delay = MINUTE;
					int count = 1;
					while (count < 8) {//立即发送、1、5、10、15、30、45、60
						logger.info("通知合作方系统："+tranxSN+"/"+orderNo);
						String ret = notifyUrl.startsWith("https") ? HttpUtil.sendHttpsPost(notifyUrl, params) : HttpUtil.sendPost(notifyUrl, params);
						logger.info("接收合作方系统["+tranxSN+"/"+orderNo+"]["+ret+"]");
						if(!"SUCCESS".equalsIgnoreCase(ret)){
							Thread.sleep(delay);
							count++;
							if (count < 4) delay = (count - 1) * 5 * MINUTE;
							if (count >= 4) delay = (count -3) * 15 * MINUTE;
						}else {
							count = 8;
						}
					}
				} catch (InterruptedException e) {
					logger.error("NotifyMessage ERROR : " + params);
					e.printStackTrace();
				}
			}
		}).start();
	}
	
	public static void notifyTransFlow(final Transflow transflow){
		new Thread(new Runnable() {
			@Override
			public void run() {
				Map<String, Object> params = new HashMap<String, Object>();
				try {
					params.put("partnerCode", transflow.getPartnerCode());
					params.put("memberNo", transflow.getMemberNo());
					params.put("tranxSN", transflow.getTranxSN());
					params.put("subject", transflow.getSubject());
					params.put("bizcode", transflow.getBizcode());
					params.put("transAmt", transflow.getTransAmt());
					params.put("transFee", transflow.getTransFee());
					final long MINUTE = 1000 * 60;
					long delay = MINUTE;
					int count = 1;
					while (count < 8) {//立即发送、1、5、10、15、30、45、60
						logger.info("通知账单系统交易记录："+transflow.getTranxSN());
						String ret = HttpUtil.sendPost(Constant.NOTIFY_TRANSURL, params);
						logger.info("接收账单系统交易记录["+transflow.getTranxSN()+"]["+ret+"]");
						if(!"SUCCESS".equals(ret)){
							Thread.sleep(delay);
							count++;
							if (count < 4) delay = (count - 1) * 5 * MINUTE;
							if (count >= 4) delay = (count -3) * 15 * MINUTE;
						}else {
							count = 8;
						}
					}
				} catch (InterruptedException e) {
					logger.error("NotifyTransFlow ERROR : " + params);
				}
			}
		}).start();
	}
	
	/**
	 * 生成结算流水
	 * @return
	 */
	public static String generSettNo(){
		return String.format("ST%s%s", DateUtil.formatNow("MMddHHmmssSSSS"), String.format("%04d", (int)(Math.random() * 100000)));
	}
	
	public static String getSettDate(Date date, boolean isD0) {
		String settDate = DateUtil.format(date, "yyyyMMdd");
		if (isD0) {//D0位当天实时结算
			return settDate;
		} else {
			Calendar calendar = Calendar.getInstance();      
	        calendar.setTime(date);
	        calendar.add(Calendar.DAY_OF_WEEK, 1);
//	        if (calendar.get(Calendar.HOUR_OF_DAY) > 22) {//23:00之前 如果明天不是 就找下一个
//	        	String tomorrow =  DateUtil.format(calendar.getTime(), "yyyyMMdd"), nextWorkday = getNextWorkday(date);
//	        	return tomorrow.equals(nextWorkday) ? getNextWorkday(calendar.getTime()) : nextWorkday;
//			} else {//23:30之后 如果明天是工作日
				String tomorrow =  DateUtil.format(calendar.getTime(), "yyyyMMdd"), nextWorkday = getNextWorkday(date);
				return tomorrow.equals(nextWorkday) ? tomorrow : nextWorkday;
//			}
		}
	}
	
	private static String getNextWorkday(Date date){
		Calendar calendar = Calendar.getInstance();      
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_WEEK, 1);
        date = calendar.getTime(); //先获取明天
        String dateStr = DateUtil.format(date, "yyyyMMdd");
        boolean isExists = DataDao.getInstance().getWorkDay(dateStr);
        boolean isWorkday = calendar.get(Calendar.DAY_OF_WEEK) > 1 && calendar.get(Calendar.DAY_OF_WEEK) < 7;
        if (isWorkday) {//如果明天是工作日  查询在数据库中是否存在  如果存在 查找下一个工作日  不存在返回明天
        	return isExists ? getNextWorkday(date) : dateStr;
		} else {//如果明天不是工作日  查询在数据库中是否存在  如果存在 则返回明天  不存在则 查找下一个工作日
			return isExists ? dateStr : getNextWorkday(date);
		}
	}
	/**
     * 得到请求参数
     * 
     * @param request
     * @return
     */
    public static Map<String, String> getRequestParams(HttpServletRequest request,String encoding) {
        Map<String, String> params = new HashMap<String, String>(15);
        Enumeration<String> names = request.getParameterNames();
        try {
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                String value = request.getParameter(name);
                if (StringUtil.isNotEmpty(value)) {
                    if ("GET".equalsIgnoreCase(request.getMethod())) {
                        // 如果get请求修改编码UTF-8
                        params.put(name, new String(value.getBytes("ISO-8859-1"),encoding));
                    } else {
                        params.put(name,new String(value.getBytes("ISO-8859-1"),encoding));
                    }
                } else {
                    params.put(name, "");
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.error("get请求发生编码异常:", e);
        }
        return params;
    }
}
